import pandas as pd
# parameters
combined_data_file = "combined_positions.csv"
heincke_positions = "heincke.csv"
platform_deploy_times = {
"Littorina": "2023-04-24T05:30:00",
"D298": "2023-04-24T08:50:00",
"D299": "2023-04-24T08:50:00",
"D300": "2023-04-24T08:50:00",
"D301": "2023-04-24T09:35:00",
"D302": "2023-04-24T09:35:00",
"D303": "2023-04-24T09:35:00",
}
import pandas as pd
import hvplot.pandas
from bokeh.models import HoverTool, SaveTool
import geoviews as gv
from functools import reduce
df = pd.read_csv(combined_data_file, parse_dates=["Timestamp", ])
df
| Timestamp | Longitude | Latitude | Longitude_ | Latitude_ | Platform | Type | |
|---|---|---|---|---|---|---|---|
| 0 | 2023-04-24 00:55:07+00:00 | 10.18159 | 54.32806 | 10.20000 | 54.30000 | Littorina | Vessel |
| 1 | 2023-04-24 01:55:10+00:00 | 10.18163 | 54.32806 | 10.20000 | 54.30000 | Littorina | Vessel |
| 2 | 2023-04-24 02:55:14+00:00 | 10.18160 | 54.32805 | 10.20000 | 54.30000 | Littorina | Vessel |
| 3 | 2023-04-24 03:58:09+00:00 | 10.18160 | 54.32809 | 10.20000 | 54.30000 | Littorina | Vessel |
| 4 | 2023-04-24 04:58:10+00:00 | 10.18161 | 54.32804 | 10.20000 | 54.30000 | Littorina | Vessel |
| ... | ... | ... | ... | ... | ... | ... | ... |
| 13749 | 2023-05-09 08:40:47+00:00 | 10.73319 | 54.93622 | 10.73319 | 54.93622 | D303 | Buoy |
| 13750 | 2023-05-09 08:45:46+00:00 | 10.73306 | 54.93580 | 10.73306 | 54.93580 | D303 | Buoy |
| 13751 | 2023-05-09 09:20:47+00:00 | 10.73313 | 54.93616 | 10.73313 | 54.93616 | D303 | Buoy |
| 13752 | 2023-05-09 09:25:48+00:00 | 10.73306 | 54.93605 | 10.73306 | 54.93605 | D303 | Buoy |
| 13753 | 2023-05-09 09:40:44+00:00 | 10.73317 | 54.93613 | 10.73317 | 54.93613 | D303 | Buoy |
13754 rows × 7 columns
df_heincke = pd.read_csv(heincke_positions, parse_dates=["Timestamp", ])
df_heincke["Latitude_"] = df_heincke.Latitude
df_heincke["Longitude_"] = df_heincke.Longitude
df_heincke
| Timestamp | Longitude | Latitude | Platform | Type | Latitude_ | Longitude_ | |
|---|---|---|---|---|---|---|---|
| 0 | 2023-05-08 12:58:00 | 8.58042 | 53.52311 | Heincke | Vessel | 53.52311 | 8.58042 |
| 1 | 2023-05-08 13:08:00 | 8.58042 | 53.52311 | Heincke | Vessel | 53.52311 | 8.58042 |
| 2 | 2023-05-08 13:18:00 | 8.58042 | 53.52311 | Heincke | Vessel | 53.52311 | 8.58042 |
| 3 | 2023-05-08 13:28:00 | 8.58043 | 53.52311 | Heincke | Vessel | 53.52311 | 8.58043 |
| 4 | 2023-05-08 13:38:00 | 8.58042 | 53.52311 | Heincke | Vessel | 53.52311 | 8.58042 |
| ... | ... | ... | ... | ... | ... | ... | ... |
| 67 | 2023-05-09 09:08:00 | 8.58042 | 53.52310 | Heincke | Vessel | 53.52310 | 8.58042 |
| 68 | 2023-05-09 09:18:00 | 8.58042 | 53.52310 | Heincke | Vessel | 53.52310 | 8.58042 |
| 69 | 2023-05-09 09:28:00 | 8.58042 | 53.52310 | Heincke | Vessel | 53.52310 | 8.58042 |
| 70 | 2023-05-09 09:38:00 | 8.58042 | 53.52310 | Heincke | Vessel | 53.52310 | 8.58042 |
| 71 | 2023-05-09 09:48:00 | 8.58042 | 53.52310 | Heincke | Vessel | 53.52310 | 8.58042 |
72 rows × 7 columns
hover = HoverTool(tooltips=[
("Platform", "@Platform"),
("Type", "@Type"),
("Timestamp", "@Timestamp"),
("Longitude", "@Longitude_"), # display potentially redacted positions
("Latitude", "@Latitude_"), # display potentially redacted positions
])
savetool = SaveTool()
plots = []
for npf, pf in enumerate(df.Platform.unique()):
if npf == 0:
_kwargs = dict(
tiles="OSM",
xlim=(9.8, 12.3),
ylim=(54.2, 55),
)
else:
_kwargs = {}
_df = df.where(
(df.Platform == pf)
& (df.Timestamp > platform_deploy_times[pf])
).dropna().sort_values("Timestamp")
_df["Timestamp"] = _df["Timestamp"].astype(str) # needed for proper display
plots.append(
(
_df.hvplot.paths(
x="Longitude", y="Latitude", line_width=2,
label=pf,
geo=True,
**_kwargs
)
* _df.hvplot.points(
x="Longitude", y="Latitude", size=25, marker="x",
label=pf,
hover_cols=["Platform", "Type", "Longitude_", "Latitude_", "Timestamp", ], tools=[hover, ],
geo=True,
)
)
)
plots.append(
(
df_heincke.hvplot.paths(
x="Longitude", y="Latitude", size=95, color="magenta", geo=True, label="Heincke", hover_cols=["Timestamp", ]
)
* df_heincke.iloc[-1:].hvplot.points(
x="Longitude", y="Latitude", size=95, color="magenta", marker=">", geo=True, label="Heincke", hover_cols=["Timestamp", ]
)
)
)
plot = reduce(lambda a, b: a * b, plots[1:], plots[0]).opts(frame_width=700)
now = !date -Is -u
now = now[0]
display(plot.opts(title=f"{now} UTC"));
pd.concat((df, df_heincke), ignore_index=True).groupby("Platform").tail(3).set_index(["Platform", "Timestamp"])[["Longitude_", "Latitude_"]]
| Longitude_ | Latitude_ | ||
|---|---|---|---|
| Platform | Timestamp | ||
| Littorina | 2023-05-09 06:55:06+00:00 | 10.90000 | 56.40000 |
| 2023-05-09 07:58:05+00:00 | 10.90000 | 56.40000 | |
| 2023-05-09 08:55:06+00:00 | 10.90000 | 56.40000 | |
| D298 | 2023-05-05 16:11:22+00:00 | 11.13679 | 54.48502 |
| 2023-05-05 16:16:24+00:00 | 11.13685 | 54.48501 | |
| 2023-05-05 16:22:16+00:00 | 11.13705 | 54.48495 | |
| D299 | 2023-05-06 16:01:21+00:00 | 10.13019 | 54.35603 |
| 2023-05-06 16:06:18+00:00 | 10.13015 | 54.35589 | |
| 2023-05-06 16:21:16+00:00 | 10.14892 | 54.33151 | |
| D300 | 2023-05-05 13:32:04+00:00 | 11.07306 | 54.53201 |
| 2023-05-05 13:36:27+00:00 | 11.07310 | 54.53198 | |
| 2023-05-05 13:51:27+00:00 | 11.07315 | 54.53195 | |
| D301 | 2023-05-05 06:48:59+00:00 | 10.16894 | 54.33173 |
| 2023-05-05 06:54:51+00:00 | 10.15296 | 54.33286 | |
| 2023-05-05 06:58:58+00:00 | 10.15124 | 54.33219 | |
| D302 | 2023-05-06 16:21:24+00:00 | 10.14849 | 54.33080 |
| 2023-05-06 19:36:23+00:00 | 10.14763 | 54.32993 | |
| 2023-05-06 21:52:31+00:00 | 10.14643 | 54.32990 | |
| D303 | 2023-05-09 09:20:47+00:00 | 10.73313 | 54.93616 |
| 2023-05-09 09:25:48+00:00 | 10.73306 | 54.93605 | |
| 2023-05-09 09:40:44+00:00 | 10.73317 | 54.93613 | |
| Heincke | 2023-05-09 09:28:00 | 8.58042 | 53.52310 |
| 2023-05-09 09:38:00 | 8.58042 | 53.52310 | |
| 2023-05-09 09:48:00 | 8.58042 | 53.52310 |
def generate_google_maps_link(Longitude, Latitude):
return f"https://www.google.com/maps/place/{Latitude}+{Longitude}"
links = (
pd.concat((df, df_heincke), ignore_index=True)
.groupby("Platform").tail(1)
.set_index(["Platform", "Timestamp"])
[["Longitude", "Latitude"]]
.apply(lambda r: generate_google_maps_link(**r), axis=1)
)
for r in links.items():
print(f"{r[0][0]} @ {r[0][1]}\n\t{r[1]}")
Littorina @ 2023-05-09 08:55:06+00:00 https://www.google.com/maps/place/56.41609+10.92528 D298 @ 2023-05-05 16:22:16+00:00 https://www.google.com/maps/place/54.48495+11.13705 D299 @ 2023-05-06 16:21:16+00:00 https://www.google.com/maps/place/54.33151+10.14892 D300 @ 2023-05-05 13:51:27+00:00 https://www.google.com/maps/place/54.53195+11.07315 D301 @ 2023-05-05 06:58:58+00:00 https://www.google.com/maps/place/54.33219+10.15124 D302 @ 2023-05-06 21:52:31+00:00 https://www.google.com/maps/place/54.3299+10.14643 D303 @ 2023-05-09 09:40:44+00:00 https://www.google.com/maps/place/54.93613+10.73317 Heincke @ 2023-05-09 09:48:00 https://www.google.com/maps/place/53.5231+8.58042
!date -Is -u
2023-05-09T09:57:36+00:00